package com.example.execute;

import com.example.constant.FTPConstant;
import com.example.demo.FileChooserUI;
import com.example.entity.FileMetaData;
import com.example.entity.ResponseResult;
import com.example.entity.vo.FileMetaDataVO;
import com.example.ftp.FTPUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class PlacingFilesService {

    @Autowired
    private FTPUtil ftpUtil;

    /**
     * 落盘文件：
     * 总量进度条、百分比、
     * 文件数、文件大小、
     * 速率、用时、剩余时间、操作人
     *
     * 文件数、文件大小 这两个是固定的，直接显示固定
     *
     * 下面几个是隔一段时间展示：
     * 速率 数据传输速率 = 传输的数据量 / 传输时间 传输的数据量 / 用时
     * 用时 开始上传到现在的时间间隔，记录一个开始时间，然后隔一段时间和当前时间作差得出用时，返回展示
     * 剩余时间 先估计这些文件落盘总的大概要花多少时间，减去用时
     */
    public ResponseResult placingFile(FileMetaDataVO fileMetaDataVO) throws ParseException {
        long start = System.currentTimeMillis();// 开始上传时间

        Set<FileMetaData> fileMetaDataSet = new HashSet<>();
        Set<String> fileSubNames = new HashSet<>();

        // 1、文件落盘ftp
        Path fileDir = Paths.get(fileMetaDataVO.getDirPath());

        // 扫描文件目录得出要落盘的文件绝对路径集合
        List<Path> files;
        long fileTotalSize;
        try {
            Map<String, Object> allFilesInDirectory = getAllFilesInDirectory(fileDir);
            files = (List<Path>) allFilesInDirectory.get("files");
            fileTotalSize = (long) allFilesInDirectory.get("fileTotalSize");

            FileChooserUI.fileNums = files.size();
            FileChooserUI.fileTotalSize = fileTotalSize / 1000;
        } catch (Exception e) {
            return ResponseResult.fail(e.getMessage());
        }


        try {
            // 上传文件
            long totalTime = estimateTotalCostTime(fileTotalSize);

            long l = System.currentTimeMillis();
            ftpUtil.uploadFiles(files, fileTotalSize,start,totalTime);
            long e = System.currentTimeMillis();
            System.out.println("上传文件耗时：" + (e - l));
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("落盘文件失败：" + e.getMessage());
            return ResponseResult.fail("落盘文件失败！");
        }

        /**
         * 2、文件元数据入库 如果这边报错文件不影响上面文件落盘
         * 文件名相同的文件入库一条文件元数据 FileMetaData
         */
        String fileNameSub = "";
        for (Path file : files) {
            String fileName = file.getFileName().toString();
            // 不带后缀
            fileNameSub = fileName.substring(0, fileName.lastIndexOf("."));

            if (!fileSubNames.contains(fileNameSub)) {
                // 完善文件的元数据信息 文件名一样的执行一次
                FileMetaData fileMetaData = completeFileMetaData(file, fileMetaDataVO);
                // Set 保证同一条数据的文件的元数据只会被添加一次
                fileMetaDataSet.add(fileMetaData);

                fileSubNames.add(fileNameSub);
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("文件落盘ftp耗时：" + (end - start));


        for (FileMetaData fileMetaData : fileMetaDataSet) {
//            fileMetaDataMapper.insert(fileMetaData);
        }

        return ResponseResult.success("落盘文件成功！");
    }

    /**
     * 估计落盘文件大概花费的时间
     * @param fileTotalSize
     * @return
     */
    private long estimateTotalCostTime(long fileTotalSize) {
        // 125751.6349411765 byte/ms
        double uploadSpeed = 125751.6349411765; // byte/ms

        return (long) (fileTotalSize / uploadSpeed);
    }

    /**
     * 根据文件夹目录返回文件绝对路径list
     *
     * @param directoryPath 文件夹目录
     * @return
     */
    public Map<String, Object> getAllFilesInDirectory(Path directoryPath) throws IOException {
        Map<String, Object> result = new HashMap<>();
        List<Path> filePaths;
        long totalSize;

        // 使用 Files.walk 方法来遍历文件夹及其子目录中的文件。
        // Integer.MAX_VALUE 用于设置遍历深度，FileVisitOption.FOLLOW_LINKS 表示要遵循符号链接。
        try (Stream<Path> stream = Files.walk(directoryPath, Integer.MAX_VALUE, FileVisitOption.FOLLOW_LINKS)) {
            filePaths = stream
                    .filter(Files::isRegularFile)
                    .collect(Collectors.toList());// Stream流通过collect sum等终结操作就会关闭

//            totalSize = stream
//            所以再用同一个流就会报错:java.lang.IllegalStateException: stream has already been operated upon or closed
            totalSize = filePaths.stream()
                    .filter(Files::isRegularFile)
                    .mapToLong(path -> {
                        try {
                            return Files.size(path);
                        } catch (IOException e) {
                            // 处理获取文件大小时的异常
                            e.printStackTrace();
                            return 0; // 返回 0 或者其他默认值，取决于你的需求
                        }
                    })
                    .sum();
        } catch (IOException e) {
            throw new IOException("遍历目录时发生错误: " + e.getMessage(), e);
        }
        result.put("files", filePaths);
        result.put("fileTotalSize", totalSize);
        return result;
    }

    /**
     * 完善信息
     * <p>
     * 入库要素：ID、采集地点ID、系统型号ID、目标对象（可配置、也可不配置）、采集时间（从文件名中获取）、
     * 中心频率、脉冲个数、入库时间（当前时间）、pdw格式、文件名、文件大小、文件位置、创建人（登入用户）
     * <p>
     * 2022_05_22_10_38_29_281_I_9600MHz_43803
     * 采集时间（从文件名中获取）：2022_05_22_10_38_29_281
     * 中心频率:9600MHz
     * 脉冲个数：43803
     *
     * @param file
     * @param fileMetaDataVO
     * @return
     */
    private FileMetaData completeFileMetaData(Path file, FileMetaDataVO fileMetaDataVO) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SS");
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd_HH_mm_ss_SSS");

        FileMetaData fileMetaData = new FileMetaData();
        BeanUtils.copyProperties(fileMetaDataVO, fileMetaData);

        // 解析文件名
        String fileName = file.getFileName().toString();
        // 定义正则表达式
        String pattern = "(\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{3})_I_(\\d+MHz)_(\\d+)";
        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);
        // 创建 Matcher 对象
        Matcher m = r.matcher(fileName);
        // 如果匹配成功，则提取信息
        if (m.find()) {
            fileMetaData.setGatherTime(LocalDateTime.parse(m.group(1), formatter));
            fileMetaData.setCenterFreq(m.group(2));
            fileMetaData.setPulseNum(Integer.valueOf(m.group(3)));
        } else {
            System.out.println("文件名格式不匹配");
        }

        fileMetaData.setInTime(LocalDateTime.now());
        String fileNameSub = fileName.substring(0, fileName.lastIndexOf("."));        // 不带后缀
        fileMetaData.setFileName(fileNameSub);
        fileMetaData.setFileSize((double) new File(file.toAbsolutePath().toString()).length());
        fileMetaData.setFileLocation(FTPConstant.FILES_FTP_PATH + fileNameSub);
//        fileMetaData.setCreatedBy();

        return fileMetaData;
    }
}
